package top.gokzzz.common.utils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Optional;

/**
 * BigDecimal 工具類
 *
 * @author Gok
 * @version 1.0
 */
public class BigDecimalUtil {

    /**
     * 默認精度 (小數位數)
     */
    private static final int DEFAULT_SCALE = 2;

    /**
     * 默認捨入模式
     */
    private static final RoundingMode DEFAULT_ROUNDING_MODE = RoundingMode.HALF_UP;

    /**
     * 將字符串轉換為BigDecimal
     *
     * @param str 需要轉換的字符串
     * @return 轉換後的BigDecimal物件，如果輸入為null或空字符串則返回null
     * @throws NumberFormatException 如果字符串不能被解析為有效的數字
     */
    public static BigDecimal str2BigDecimal(String str) {
        if (str == null || str.trim().isEmpty()) {
            return null;
        }
        try {
            return new BigDecimal(str.trim());
        } catch (NumberFormatException e) {
            throw new NumberFormatException("無法將字符串 '" + str + "' 轉換為BigDecimal: " + e.getMessage());
        }
    }

    /**
     * 加法操作
     *
     * @param a 第一個加數
     * @param b 第二個加數
     * @return 兩數之和
     */
    public static BigDecimal add(BigDecimal a, BigDecimal b) {
        return Optional.ofNullable(a).orElse(BigDecimal.ZERO)
                .add(Optional.ofNullable(b).orElse(BigDecimal.ZERO));
    }

    /**
     * 多個數值相加
     *
     * @param values 要相加的數值
     * @return 所有數值之和
     */
    public static BigDecimal add(BigDecimal... values) {
        BigDecimal result = BigDecimal.ZERO;
        if (values != null) {
            for (BigDecimal value : values) {
                result = add(result, value);
            }
        }
        return result;
    }

    /**
     * 減法操作
     *
     * @param a 被減數
     * @param b 減數
     * @return 差值
     */
    public static BigDecimal subtract(BigDecimal a, BigDecimal b) {
        return Optional.ofNullable(a).orElse(BigDecimal.ZERO)
                .subtract(Optional.ofNullable(b).orElse(BigDecimal.ZERO));
    }

    /**
     * 乘法操作
     *
     * @param numbers 要相乘的数字，可以传入任意数量
     * @return 所有数字的乘积，如果任何参数为null则返回BigDecimal.ZERO
     */
    public static BigDecimal multiply(BigDecimal... numbers) {
        if (numbers == null || numbers.length == 0) {
            return BigDecimal.ZERO;
        }

        BigDecimal result = BigDecimal.ONE;
        for (BigDecimal number : numbers) {
            if (number == null) {
                return BigDecimal.ZERO;
            }
            result = result.multiply(number);
        }
        return result;
    }

    /**
     * 除法操作，使用默認精度和捨入模式
     *
     * @param a 被除數
     * @param b 除數
     * @return 商
     * @throws ArithmeticException 如果除數為零
     */
    public static BigDecimal divide(BigDecimal a, BigDecimal b) {
        return divide(a, b, DEFAULT_SCALE, DEFAULT_ROUNDING_MODE);
    }

    /**
     * 除法操作，指定精度和捨入模式
     *
     * @param a 被除數
     * @param b 除數
     * @param scale 精度 (小數位數)
     * @param roundingMode 捨入模式
     * @return 商
     * @throws ArithmeticException 如果除數為零
     */
    public static BigDecimal divide(BigDecimal a, BigDecimal b, int scale, RoundingMode roundingMode) {
        if (a == null) {
            return BigDecimal.ZERO;
        }
        if (b == null || BigDecimal.ZERO.compareTo(b) == 0) {
            throw new ArithmeticException("除數不能為零");
        }
        return a.divide(b, scale, roundingMode);
    }

    /**
     * 設置 BigDecimal 的小數位數
     * 會去掉末尾的零
     *
     * @param value 原始值
     * @param scale 小數位數
     * @return 處理後的值
     */
    public static BigDecimal setScale(BigDecimal value, int scale) {
        if (value == null) {
            return null;
        }
        BigDecimal scaled = value.setScale(scale, DEFAULT_ROUNDING_MODE);
        return removeTrailingZeros(scaled);
    }

    /**
     * 移除 BigDecimal 末尾的零
     * @param value 原始的 BigDecimal 值
     * @return 移除末尾零後的 BigDecimal
     */
    public static BigDecimal removeTrailingZeros(BigDecimal value) {
        if (value == null) {
            return null;
        }

        BigDecimal stripped = value.stripTrailingZeros();
        if (stripped.scale() < 0) {
            return new BigDecimal(stripped.toPlainString());
        }
        return stripped;
    }



    /**
     * 向上取整數
     *
     * @param value 原始值
     * @return {@link BigDecimal }
     */
    public static BigDecimal ceil(BigDecimal value) {
        return setScale(value, 0, RoundingMode.CEILING);
    }

    /**
     * 設置 BigDecimal 的小數位數（使用默認舍入模式）
     * @param value 原始值
     * @param scale 小數位數
     * @param roundingMode 舍入模式
     * @return 處理後的值
     */
    public static BigDecimal setScale(BigDecimal value, int scale, RoundingMode roundingMode) {
        if (value == null) {
            return null;
        }
        return value.setScale(scale, roundingMode != null ? roundingMode : DEFAULT_ROUNDING_MODE);
    }

}
